#ifndef TESTERSHAREDOUTPUTBOXIMPL_H_JM_20130125
#define TESTERSHAREDOUTPUTBOXIMPL_H_JM_20130125

// ## jm4bbx
#include "SharedOutputStreamBuffer.h"
#include "../../boxes/input/DataProviderImpls.h"
#include "../../runtime/AutomaticBoxCreatorRegistration.h"
#include "../boxes/SharedOutputBox.h"
// ## c++
#include <sstream>
#include <iostream>
#include <algorithm>

namespace jm4bbx {
	
	/**
	 * Implemantacia chovania pre SharedOutputBox, ktora vysledky vypoctu 
	 * modelu, ktore lezu do zdielaneho boxu, porovnava s predlohou dat. 
	 * Vyuziva sa pri testovani. 
	 **/
	class  TesterSharedOutputBoxImpl  
		: public SharedOutputStreamBuffer::SharedOutputCloseListener {
	public:

		TesterSharedOutputBoxImpl();

		/// Stream do ktoreho tlaci model vysledky svojho vypoctu.
		StreamWriterBox::OutputStream& getOutputStream() { 				
			return stream_;
		}

		/// Provider, ktory poskytne data (predlohu) na porovnanie s vysledkami 
		/// vypoctu modelu.
		virtual DataProvider* getDataProvider() = 0;
		
		/// Specifikacia dat pre provider.
		virtual std::string getDataSpecification() const = 0;

		/// 
		virtual size_t getSharedOutputCount() const = 0;
		/// 
		virtual std::string getTestName() const = 0;
		/// Implementacia SharedOutputCloseListener-u pre detekovanie postupneho 
		/// zatvarania vsetkych vystupov modelu. 
		/// Listener sa vklada do SharedOutputStreamBuffer streamu, resp. 
		/// membra stream_. Po zavreti posledneho vystupu je vykonana kontrola
		/// zhody vypoctu modelu a predlohy dat.
		virtual void streamClosed() override;

		/// Kontrola riadkov.
		/// @param testedRow cislo testovaneho riadku
		/// @param fails pocitadlo chyb
		/// @param r predloha (pozadovana hodnota riadku)
		/// @param b vysledok (vypocitana hodnota modelom)
		void check(size_t testedRow, int& fails, const std::string& r, 
			const std::string& b) const;

		/// Kontrola celych sad dat.
		/// @param requiredResult predloha - pozadovany vysledok
		/// @param buffer vypocitany vysledok vlozeny do bufferu
		void compare(SharedOutputStreamBuffer::Buffer& requiredResult, 
			SharedOutputStreamBuffer::Buffer& buffer);

		/// Nastavenie poctu vystupov modelu, ktore budu liat data do bufferu.
		///void setSharedOutputs(int count) { sharedOutputs_ = count; }
		template<class boxImplType>
		void registerBox(const char* boxName) {
			typedef SharedOutputBox<boxImplType> OutputBoxType;
			AutomaticBoxCreatorRegistration<PlainBoxModelCreator<OutputBoxType>> 
				registrator(boxName, 0);
		}
	private:
		//int sharedOutputs_;
		int closedStreams_;
		SharedOutputStreamBuffer stream_;
		mutable bool errorHandled_;		
	};


	template<class T>
	class TesterSharedOutputBoxImplTemplate : public TesterSharedOutputBoxImpl {
	public:
		virtual DataProvider* getDataProvider() override {
			return &provider_;
		};
	private:
		T provider_;
	};


	typedef TesterSharedOutputBoxImplTemplate<CsvDataProvider> 
		TesterSharedOutputBoxImplCsv;

	typedef TesterSharedOutputBoxImplTemplate<SqlDataProvider> 
		TesterSharedOutputBoxImplSql;

	typedef TesterSharedOutputBoxImplTemplate<HardCodedDataProvider> 
		TesterSharedOutputBoxImplHDData;
} // namespace jm4bbx

#endif
